package cLog

import (
	"encoding/json"
	"fmt"
	"slices"
	"sort"
	"strings"

	"github.com/sirupsen/logrus"

	"gitee.com/csingo/cCommon"
)

func toMapping(entry *logrus.Entry) (result map[string]any) {
	result = make(map[string]any)

	if len(log_config.WithFields) > 0 {
		for k, v := range log_config.WithFields {
			result[k] = v
		}
	}

	if entry == nil {
		return
	}

	for k, v := range entry.Data {
		result[k] = v
	}

	result[LOG_FIELD_DATETIME] = entry.Time.Format("2006-01-02 15:04:05")
	result[LOG_FIELD_LEVEL] = entry.Level
	result[LOG_FIELD_MESSAGE] = entry.Message

	return
}

func format(entry *logrus.Entry, f FormatterInterface) (result string, err error) {
	data := toMapping(entry)

	switch f.GetFormat() {
	default:
		fallthrough
	case LOG_FORMAT_JSON:
		result, err = formatJson(data)
	case LOG_FORMAT_TEXT:
		result, err = formatText(data, f.GetColorful())
	}

	return
}

func formatJson(data map[string]any) (result string, err error) {
	var out []byte
	out, err = json.Marshal(data)
	if err != nil {
		return
	}
	result = string(out)
	return
}

func formatText(data map[string]any, colorful bool) (result string, err error) {
	var colorKeys = []string{
		LOG_FIELD_DATETIME,
		LOG_FIELD_LEVEL,
		LOG_FIELD_MESSAGE,
		strings.ToLower(cCommon.XIndex_TraceId),
	}

	var colorDatetime = "\x1b[0m"
	var colorLevel = "\x1b[0m"
	var colorOther = "\x1b[0m"
	var colorReset = "\x1b[0m"

	if colorful {
		colorDatetime = "\x1b[90m"
		colorOther = "\x1b[90m"
		switch data[LOG_FIELD_LEVEL].(logrus.Level) {
		case logrus.PanicLevel:
			fallthrough
		case logrus.FatalLevel:
			fallthrough
		case logrus.ErrorLevel:
			colorLevel = "\x1b[31m"
		case logrus.WarnLevel:
			colorLevel = "\x1b[33m"
		case logrus.InfoLevel:
			colorLevel = "\x1b[32m"
		case logrus.DebugLevel:
			colorLevel = "\x1b[34m"
		case logrus.TraceLevel:
			colorLevel = "\x1b[35m"
		}
	}

	result = fmt.Sprintf("%s%-19s%s", colorDatetime, data[LOG_FIELD_DATETIME], colorReset)
	level := strings.ToUpper(data[LOG_FIELD_LEVEL].(logrus.Level).String())
	result = fmt.Sprintf("%s | %s%-7s%s", result, colorLevel, level, colorReset)

	result = fmt.Sprintf("%s | %s | %s%s%s | ", result, data[LOG_FIELD_MESSAGE], colorOther, data[strings.ToLower(cCommon.XIndex_TraceId)], colorReset)

	var keys []string
	for k := range data {
		if !slices.Contains(colorKeys, k) {
			keys = append(keys, k)
		}
	}

	klen := len(keys)

	if klen == 0 {
		result = strings.TrimRight(result, " | ")
		return
	}

	sort.Strings(keys)

	for n, key := range keys {
		var value string
		switch data[key].(type) {
		case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64:
			value = fmt.Sprintf("%v", data[key])
		case string:
			value = data[key].(string)
		default:
			b, _ := json.Marshal(data[key])
			value = string(b)
		}

		result = fmt.Sprintf("%s%s", result, colorOther)
		result = fmt.Sprintf("%s%s%s", result, value, colorReset)
		if n < klen-1 {
			result = fmt.Sprintf("%s | ", result)
		}
	}

	return
}
